using System;
using System.Collections.Generic;
using System.Net;
using CodePlex.TfsLibrary.ObjectModel;
using CodePlex.TfsLibrary.RepositoryWebSvc;
using CodePlex.UnitTestUtility;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class TfsEngineStatusTest
    {
        static void AssertValidItem(SourceItem item,
                                    int itemId,
                                    ItemType itemType,
                                    string localName,
                                    int localChangesetId,
                                    SourceItemStatus localItemStatus,
                                    string remoteName,
                                    int remoteChangesetId,
                                    SourceItemStatus remoteItemStatus,
                                    string downloadUrl)
        {
            Assert.Equal(itemId, item.ItemId);
            Assert.Equal(itemType, item.ItemType);
            Assert.Equal(localName, item.LocalName);
            Assert.Equal(localChangesetId, item.LocalChangesetId);
            Assert.Equal(localItemStatus, item.LocalItemStatus);
            Assert.Equal(remoteName, item.RemoteName);
            Assert.Equal(remoteChangesetId, item.RemoteChangesetId);
            Assert.Equal(remoteItemStatus, item.RemoteItemStatus);
            Assert.Equal(downloadUrl, item.DownloadUrl);
        }

        public class AcceptanceTests
        {
            [Fact]
            public void AcceptanceTest()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\unmodified.txt", "unmodified");
                engine.FileSystem.WriteAllText(@"C:\Foo\modified.txt", "to be modified");
                engine.FileSystem.WriteAllText(@"C:\Foo\add.txt", "added");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\unmodified.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\modified.txt", 5, 6, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\add.txt", 0, 0, SourceItemStatus.Add);
                engine.FileSystem.WriteAllText(@"C:\Foo\modified.txt", "modified");
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/unmodified.txt", 20, 0, DateTime.Now, "dt1"),
                                      SourceItem.FromRemoteItem(9, ItemType.File, "$/Foo/serveradd.txt", 20, 0, DateTime.Now, "dt3"),
                                      SourceItem.FromRemoteItem(42, ItemType.Folder, "$/Foo/Baz", 20, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(46, ItemType.File, "$/Foo/Baz/serveradd.txt", 20, 0, DateTime.Now, "dt5"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(8, result.Count);
                AssertValidItem(result[1], 0, ItemType.File, @"C:\Foo\add.txt", 0, SourceItemStatus.Add,
                                null, 0, SourceItemStatus.None, null);
                AssertValidItem(result[2], 0, ItemType.Folder, @"C:\Foo\Bar", 0, SourceItemStatus.Unversioned,
                                null, 0, SourceItemStatus.None, null);
                AssertValidItem(result[3], 42, ItemType.Folder, @"C:\Foo\Baz", 0, SourceItemStatus.None,
                                "$/Foo/Baz", 20, SourceItemStatus.Add, null);
                AssertValidItem(result[4], 46, ItemType.File, @"C:\Foo\Baz\serveradd.txt", 0, SourceItemStatus.None,
                                "$/Foo/Baz/serveradd.txt", 20, SourceItemStatus.Add, "dt5");
                AssertValidItem(result[5], 5, ItemType.File, @"C:\Foo\modified.txt", 6, SourceItemStatus.Modified,
                                null, 0, SourceItemStatus.Delete, null);
                AssertValidItem(result[6], 9, ItemType.File, @"C:\Foo\serveradd.txt", 0, SourceItemStatus.None,
                                "$/Foo/serveradd.txt", 20, SourceItemStatus.Add, "dt3");
                AssertValidItem(result[7], 3, ItemType.File, @"C:\Foo\unmodified.txt", 4, SourceItemStatus.Unmodified,
                                "$/Foo/unmodified.txt", 20, SourceItemStatus.Modified, "dt1");
            }

            static List<SourceItem> GetStatusItems(TestableTfsEngine engine,
                                                   string localPath)
            {
                List<SourceItem> items = new List<SourceItem>();

                engine.Status(localPath, VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             items.Add(item);
                                                                         });

                return items;
            }

            [Fact]
            public void LocalAdded_DifferentServerAdded()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 0, 0, SourceItemStatus.Add);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(19, ItemType.File, "$/Foo/serveradd.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(3, result.Count);
                AssertValidItem(result[1], 0, ItemType.File, @"C:\Foo\file.txt", 0, SourceItemStatus.Add,
                                null, 0, SourceItemStatus.None, null);
                AssertValidItem(result[2], 19, ItemType.File, @"C:\Foo\serveradd.txt", 0, SourceItemStatus.None,
                                "$/Foo/serveradd.txt", 20, SourceItemStatus.Add, "dt");
            }

            [Fact]
            public void LocalAdded_ServerAdded()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 0, 0, SourceItemStatus.Add);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(19, ItemType.File, "$/Foo/file.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 19, ItemType.File, @"C:\Foo\file.txt", 0, SourceItemStatus.Add,
                                "$/Foo/file.txt", 20, SourceItemStatus.Add, "dt");
            }

            [Fact]
            public void LocalAdded_ServerUnmodified()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 0, 0, SourceItemStatus.Add);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 0, ItemType.File, @"C:\Foo\file.txt", 0, SourceItemStatus.Add,
                                null, 0, SourceItemStatus.None, null);
            }

            [Fact]
            public void LocalDeleted_ServerDeleted()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Delete);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Delete,
                                null, 0, SourceItemStatus.Delete, null);
            }

            [Fact]
            public void LocalDeleted_ServerUnmodified()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Delete);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/file.txt", 4, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Delete,
                                "$/Foo/file.txt", 4, SourceItemStatus.Unmodified, "dt");
            }

            [Fact]
            public void LocalModified_ServerDeleted()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "new file");
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Modified,
                                null, 0, SourceItemStatus.Delete, null);
            }

            [Fact]
            public void LocalModified_ServerModified()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "new file");
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/file.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Modified,
                                "$/Foo/file.txt", 20, SourceItemStatus.Modified, "dt");
            }

            [Fact]
            public void LocalUnmodified_ServerAdded()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/file.txt", 4, 0, DateTime.Now, "dt"),
                                      SourceItem.FromRemoteItem(19, ItemType.File, "$/Foo/serveradd.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(3, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Unmodified,
                                "$/Foo/file.txt", 4, SourceItemStatus.Unmodified, "dt");
                AssertValidItem(result[2], 19, ItemType.File, @"C:\Foo\serveradd.txt", 0, SourceItemStatus.None,
                                "$/Foo/serveradd.txt", 20, SourceItemStatus.Add, "dt");
            }

            [Fact]
            public void LocalUnmodified_ServerDeleted()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Unmodified,
                                null, 0, SourceItemStatus.Delete, null);
            }

            [Fact]
            public void LocalUnmodified_ServerModified()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/file.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Unmodified,
                                "$/Foo/file.txt", 20, SourceItemStatus.Modified, "dt");
            }

            [Fact]
            public void LocalUnmodified_ServerUnmodified()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/file.txt", 4, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[0], 1, ItemType.Folder, @"C:\Foo", 2, SourceItemStatus.Unmodified,
                                "$/Foo", 2, SourceItemStatus.Unmodified, null);
                AssertValidItem(result[1], 3, ItemType.File, @"C:\Foo\file.txt", 4, SourceItemStatus.Unmodified,
                                "$/Foo/file.txt", 4, SourceItemStatus.Unmodified, "dt");
            }

            [Fact]
            public void LocalUnversioned()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 0, ItemType.File, @"C:\Foo\file.txt", 0, SourceItemStatus.Unversioned,
                                null, 0, SourceItemStatus.None, null);
            }

            [Fact]
            public void LocalUnversioned_ServerAdded()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\file.txt", "file");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(19, ItemType.File, "$/Foo/file.txt", 20, 0, DateTime.Now, "dt"));

                List<SourceItem> result = GetStatusItems(engine, @"C:\Foo");

                Assert.Equal(2, result.Count);
                AssertValidItem(result[1], 19, ItemType.File, @"C:\Foo\file.txt", 0, SourceItemStatus.Unversioned,
                                "$/Foo/file.txt", 20, SourceItemStatus.Add, "dt");
            }
        }

        public class Status
        {
            [Fact]
            public void CallsQueryItemsForStatusWithServer()
            {
                ICredentials creds = new NetworkCredential("joe", "bob");
                VersionSpec version = VersionSpec.Latest;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.CredentialsCallback += delegate
                                              {
                                                  return creds;
                                              };

                engine.Status(@"C:\Foo", version, true, true, delegate {});

                Assert.Equal("http://tfsUrl", engine.SourceControlService.QueryItems_TfsUrl);
                Assert.Same(creds, engine.SourceControlService.QueryItems_Credentials);
                Assert.Equal("$/Foo/", engine.SourceControlService.QueryItems_ServerPath);
                Assert.Equal(RecursionType.Full, engine.SourceControlService.QueryItems_Recursion);
                Assert.Equal(version, engine.SourceControlService.QueryItems_VersionSpec);
                Assert.Equal(DeletedState.NonDeleted, engine.SourceControlService.QueryItems_DeletedState);
                Assert.Equal(ItemType.Any, engine.SourceControlService.QueryItems_ItemType);
            }

            [Fact]
            public void NullCallback()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Status(@"C:\Foo", VersionSpec.Latest, true, false, null);
                                                     });
            }

            [Fact]
            public void NullLocalPath()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Status(null, VersionSpec.Latest, true, false, delegate {});
                                                     });
            }

            [Fact]
            public void NullVersionSpec()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Status(@"C:\Foo", null, true, false, delegate {});
                                                     });
            }

            [Fact]
            public void PathNotFound()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, true, delegate(SourceItem item,
                                                                                   SourceItemResult result)
                                                                          {
                                                                              callbackItem = item;
                                                                              callbackResult = result;
                                                                          });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_PathNotFound, callbackResult);
            }

            [Fact]
            public void UsesCallbackToGetCredentials()
            {
                bool callbackCalled = false;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.CredentialsCallback += delegate
                                              {
                                                  callbackCalled = true;
                                                  return null;
                                              };

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, true, delegate {});

                Assert.True(callbackCalled);
            }
        }

        public class Status_LocalOnly_File
        {
            [Fact]
            public void NotInAWorkingFolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, false, false, delegate(SourceItem item,
                                                                                            SourceItemResult result)
                                                                                   {
                                                                                       callbackItem = item;
                                                                                       callbackResult = result;
                                                                                   });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_NotInAWorkingFolder, callbackResult);
            }

            [Fact]
            public void Unmodified()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 2, 1, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, false, false, delegate(SourceItem item,
                                                                                            SourceItemResult result)
                                                                                   {
                                                                                       callbackItem = item;
                                                                                       callbackResult = result;
                                                                                   });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unversioned()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, false, false, delegate(SourceItem item,
                                                                                            SourceItemResult result)
                                                                                   {
                                                                                       callbackItem = item;
                                                                                       callbackResult = result;
                                                                                   });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Status_LocalOnly_Folder
        {
            [Fact]
            public void NonRecursive()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, false, delegate
                                                                           {
                                                                               ++itemCount;
                                                                           });

                Assert.Equal(3, itemCount); // Bar, file1.txt, file2.txt
            }

            [Fact]
            public void NotInAWorkingFolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, false, delegate(SourceItem item,
                                                                                   SourceItemResult result)
                                                                          {
                                                                              callbackItem = item;
                                                                              callbackResult = result;
                                                                          });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_NotInAWorkingFolder, callbackResult);
            }

            [Fact]
            public void Recursive()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, false, delegate
                                                                          {
                                                                              ++itemCount;
                                                                          });

                Assert.Equal(4, itemCount); // Bar, file1.txt, file2.txt, Bar\file3.txt
            }

            [Fact]
            public void Recursive_DoNotAddMergeFiles()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt.mine", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt.r123", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, false, delegate
                                                                          {
                                                                              ++itemCount;
                                                                          });

                Assert.Equal(4, itemCount);
            }

            [Fact]
            public void Recursive_Ignore()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.IgnoreList.Ignores.Add(@"C:\Foo\Bar\file3.txt");
                engine.IgnoreList.Ignores.Add(@"C:\Foo\Bar\file4.txt");
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file4.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, false, delegate
                                                                          {
                                                                              ++itemCount;
                                                                          });

                Assert.Equal(4, itemCount); // Bar, file1.txt, file2.txt, Bar\file3.txt
            }

            [Fact]
            public void ValidatesDirectory()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, false, delegate {});

                Assert.Equal(@"C:\Foo", engine.ValidateDirectoryStructure_Directory);
            }
        }

        public class Status_WithServer
        {
            [Fact]
            public void PathNotFound()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             callbackItem = item;
                                                                             callbackResult = result;
                                                                         });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_PathNotFound, callbackResult);
            }
        }

        public class Status_WithServer_File
        {
            [Fact]
            public void AddedLocal()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Add);
                engine.StubQueryItems();

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Add, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.None, callbackItem.RemoteItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void DeletedLocal()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Delete);
                engine.StubQueryItems(SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/bar.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void MissingLocal()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteFile(@"C:\Foo\bar.txt");
                engine.StubQueryItems(SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/bar.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void ModifiedLocal()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is modified text");
                engine.StubQueryItems(SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/bar.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void NotInAWorkingFolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_NotInAWorkingFolder, callbackResult);
            }

            [Fact]
            public void UnmodifiedLocal()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(3, ItemType.File, "$/Foo/bar.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unversioned()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                          SourceItemResult result)
                                                                                 {
                                                                                     callbackItem = item;
                                                                                     callbackResult = result;
                                                                                 });

                Assert.Equal(@"C:\Foo\bar.txt", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unversioned_Ignored()
            {
                List<SourceItemCallbackData> results = new List<SourceItemCallbackData>();
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.IgnoreList.Ignores.Add(@"C:\Foo\bar.txt");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             results.Add(new SourceItemCallbackData(item, result));
                                                                         });

                Assert.Equal(1, results.Count);
                Assert.Equal(@"C:\Foo", results[0].SourceItem.LocalName);
            }

            [Fact]
            public void UnversionedLocally_ServerAdded_Ignored()
            {
                List<SourceItemCallbackData> results = new List<SourceItemCallbackData>();
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.IgnoreList.Ignores.Add(@"C:\Foo\bar.txt");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(5, ItemType.File, "$/Foo/bar.txt", 6, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             results.Add(new SourceItemCallbackData(item, result));
                                                                         });

                Assert.Equal(2, results.Count);
                Assert.Equal(@"C:\Foo", results[0].SourceItem.LocalName);
                Assert.Equal(@"C:\Foo\bar.txt", results[1].SourceItem.LocalName);
            }

            [Fact]
            public void ValidatesDirectory()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "This is text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo\bar.txt", VersionSpec.Latest, false, true, delegate {});

                Assert.Equal(@"C:\Foo", engine.ValidateDirectoryStructure_Directory);
            }
        }

        public class Status_WithServer_Folder
        {
            [Fact]
            public void NotInAWorkingFolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             callbackItem = item;
                                                                             callbackResult = result;
                                                                         });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemResult.E_NotInAWorkingFolder, callbackResult);
            }

            [Fact]
            public void Unmodified_Ignored()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.IgnoreList.Ignores.Add(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             callbackItem = item;
                                                                             callbackResult = result;
                                                                         });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unmodified_Root()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             callbackItem = item;
                                                                             callbackResult = result;
                                                                         });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unmodified_Subfolder()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo/Bar", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo\Bar", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                      SourceItemResult result)
                                                                             {
                                                                                 callbackItem = item;
                                                                                 callbackResult = result;
                                                                             });

                Assert.Equal(@"C:\Foo\Bar", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unversioned()
            {
                SourceItem callbackItem = null;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo\Bar", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                      SourceItemResult result)
                                                                             {
                                                                                 callbackItem = item;
                                                                                 callbackResult = result;
                                                                             });

                Assert.Equal(@"C:\Foo\Bar", callbackItem.LocalName);
                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void Unversioned_Ignored()
            {
                List<SourceItemCallbackData> results = new List<SourceItemCallbackData>();
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.IgnoreList.Ignores.Add(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             results.Add(new SourceItemCallbackData(item, result));
                                                                         });

                Assert.Equal(1, results.Count);
                AssertValidItem(results[0].SourceItem, 1, ItemType.Folder, @"C:\Foo", 2, SourceItemStatus.Unmodified, "$/Foo", 2, SourceItemStatus.Unmodified, null);
            }

            [Fact]
            public void UnversionedLocally_ServerAdded_Ignored()
            {
                SourceItem callbackItem = null;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.IgnoreList.Ignores.Add(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(1, ItemType.Folder, "$/Foo", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(5, ItemType.Folder, "$/Foo/Bar", 6, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate(SourceItem item,
                                                                                  SourceItemResult result)
                                                                         {
                                                                             callbackItem = item;
                                                                         });

                Assert.Equal(@"C:\Foo\Bar", callbackItem.LocalName);
            }

            [Fact]
            public void ValidatesDirectory()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, true, delegate {});

                Assert.Equal(@"C:\Foo", engine.ValidateDirectoryStructure_Directory);
            }
        }

        public class Status_WithServer_Hierarchy
        {
            [Fact]
            public void NonRecursive_NoServerUpdates()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath/Bar", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(1, ItemType.File, "$/ServerPath/file1.txt", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/ServerPath/file2.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, true, delegate
                                                                          {
                                                                              ++itemCount;
                                                                          });

                Assert.Equal(4, itemCount);
            }

            [Fact]
            public void NonRecursive_ServerUpdates()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath/Bar", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(7, ItemType.File, "$/ServerPath/biff.txt", 8, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(1, ItemType.File, "$/ServerPath/file1.txt", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/ServerPath/file2.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, false, true, delegate
                                                                          {
                                                                              ++itemCount;
                                                                          });

                Assert.Equal(5, itemCount);
            }

            [Fact]
            public void Recursive_ServerUpdates()
            {
                int itemCount = 0;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\file1.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\file2.txt", "text");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\file3.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/", @"C:\Foo", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/ServerPath/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file1.txt", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\file2.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\file3.txt", 5, 6, SourceItemStatus.Unmodified);
                engine.StubQueryItems(SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(0, ItemType.Folder, "$/ServerPath/Bar", 0, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(5, ItemType.File, "$/ServerPath/Bar/file3.txt", 6, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(7, ItemType.File, "$/ServerPath/biff.txt", 8, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(1, ItemType.File, "$/ServerPath/file1.txt", 2, 0, DateTime.Now, null),
                                      SourceItem.FromRemoteItem(3, ItemType.File, "$/ServerPath/file2.txt", 4, 0, DateTime.Now, null));

                engine.Status(@"C:\Foo", VersionSpec.Latest, true, true, delegate
                                                                         {
                                                                             ++itemCount;
                                                                         });

                Assert.Equal(6, itemCount);
            }
        }
    }
}